// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package reflect

// VisibleFields返回t中的所有可见字段，它必须是
// 结构类型。如果可以通过FieldByName调用直接访问某个字段，则该字段定义为可见。返回的字段包括匿名结构成员内的字段
// 和未报告的字段。它们的顺序与在结构中找到的顺序相同，匿名字段紧跟在升级字段后面。
// 
// 对于返回切片的每个元素e，可以通过调用v.FieldByIndex（e.Index）从类型为t的值v中检索相应的字段
// 。
func VisibleFields(t Type) []StructField {
	if t == nil {
		panic("reflect: VisibleFields(nil)")
	}
	if t.Kind() != Struct {
		panic("reflect.VisibleFields of non-struct type")
	}
	w := &visibleFieldsWalker{
		byName:   make(map[string]int),
		visiting: make(map[Type]bool),
		fields:   make([]StructField, 0, t.NumField()),
		index:    make([]int, 0, 2),
	}
	w.walk(t)
	// 删除所有隐藏的字段。
	// 使用就地删除，避免在
	// 没有隐藏字段的常见情况下复制。
	j := 0
	for i := range w.fields {
		f := &w.fields[i]
		if f.Name == "" {
			continue
		}
		if i != j {
			// 已删除一个字段。我们需要重新整理
			// 所有后续元素。
			w.fields[j] = *f
		}
		j++
	}
	return w.fields[:j]
}

type visibleFieldsWalker struct {
	byName   map[string]int
	visiting map[Type]bool
	fields   []StructField
	index    []int
}

// walk遍历t型结构中的所有字段，访问索引前序中的
// 字段，并将它们附加到w字段
// （这保持了所需的顺序）。
// 已被覆盖的字段的
// 名称字段已清除。
func (w *visibleFieldsWalker) walk(t Type) {
	if w.visiting[t] {
		return
	}
	w.visiting[t] = true
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		w.index = append(w.index, i)
		add := true
		if oldIndex, ok := w.byName[f.Name]; ok {
			old := &w.fields[oldIndex]
			if len(w.index) == len(old.Index) {
				// 相同深度的同名字段
				// 相互抵消。将字段名
				// 设置为空表示已发生，
				// 无需添加此字段。
				old.Name = ""
				add = false
			} else if len(w.index) < len(old.Index) {
				// 旧的领域失败了，因为它比新的领域更深。
				old.Name = ""
			} else {
				// 旧球场获胜，因为它比新球场浅。
				add = false
			}
		}
		if add {
			// 复制索引，使其不会被其他附录覆盖。
			f.Index = append([]int(nil), w.index...)
			w.byName[f.Name] = len(w.fields)
			w.fields = append(w.fields, f)
		}
		if f.Anonymous {
			if f.Type.Kind() == Pointer {
				f.Type = f.Type.Elem()
			}
			if f.Type.Kind() == Struct {
				w.walk(f.Type)
			}
		}
		w.index = w.index[:len(w.index)-1]
	}
	delete(w.visiting, t)
}
